package com.mxpio.erp.plm.service.impl;


import com.mxpio.erp.common.enums.PlmEnums;
import com.mxpio.erp.common.plm.entity.ProjectInfo;
import com.mxpio.erp.common.plm.entity.ProjectReport;
import com.mxpio.erp.common.plm.entity.ProjectTask;
import com.mxpio.erp.common.plm.service.ProjectInfoService;
import com.mxpio.erp.common.plm.service.ProjectReportService;
import com.mxpio.erp.common.plm.service.ProjectTaskService;
import com.mxpioframework.jpa.JpaUtil;
import com.mxpioframework.jpa.query.Criteria;
import com.mxpioframework.jpa.query.Operator;
import com.mxpioframework.security.entity.Dept;
import com.mxpioframework.security.entity.Dict;
import com.mxpioframework.security.entity.DictItem;
import com.mxpioframework.security.service.DeptService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class ProjectReportServiceImpl implements ProjectReportService {

    @Autowired
    private DeptService deptService;

    @Autowired
    private ProjectInfoService projectInfoService;
    @Autowired
    private ProjectTaskService projectTaskService;
    @Override
    @Transactional
    public List<ProjectReport> getCount(String infoDeptId) {
        //查询部门以及子部门
        Dept dept = JpaUtil.linq(Dept.class).equal("deptCode", infoDeptId).findOne();
        List<String> deptCodes    =  getchildren(dept);
        deptCodes.add(dept.getDeptCode());

        // 获取当前日期
        LocalDate currentDate = LocalDate.now();
        // 从当前日期中提取年份
        int year = currentDate.getYear();
        Calendar calendar = new GregorianCalendar(year, Calendar.JANUARY, 1, 0, 0, 0);
        calendar.set(Calendar.MILLISECOND, 0); // 精确到秒，所以毫秒设为0
        Date startDate = calendar.getTime();
        calendar.set(Calendar.MONTH, Calendar.DECEMBER);
        calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        calendar.set(Calendar.MILLISECOND, 999); // 如果需要精确到毫秒的最后一位，可以设为999，否则设为0以保持秒级精度
        // 但由于要求精确到秒，这里我们再次将其设为0以保持一致性
        calendar.set(Calendar.MILLISECOND, 0);
        Date endDate = calendar.getTime();
        Criteria criteria = Criteria.create();
//        criteria.addCriterion("createTime",Operator.GE,startDate);
//        criteria.addCriterion("createTime",Operator.LE,endDate);
        criteria.addCriterion("infoDeptId",Operator.IN,deptCodes);//对应的公司部门
        List<ProjectInfo> list = JpaUtil.linq(ProjectInfo.class).where(criteria).list();


        int newNum = 0;//新增数量
        int completionNum = 0;//已完成数量
        int overdueCompletionNum = 0;//逾期完成数量
        int executeNum = 0;//执行中数量
        int overdueExecuteNum = 0;//逾期执行中数量
        int pauseNum = 0;//暂停数量
        int endNum = 0;//已终止数量
        for (ProjectInfo projectInfo : list) {
//            只查询对应的是项目所属部门
//            if (StringUtils.equals(projectInfo.getInfoDeptId(),infoDeptId)){

                //新增数量
                if (StringUtils.equals(projectInfo.getProStatus(), PlmEnums.ProStatus.NEW.getCode())) {
                    newNum = newNum + 1;
                    continue;
                }
                //已完成
                if (StringUtils.equals(projectInfo.getProStatus(), PlmEnums.ProStatus.FINISH.getCode())) {
                    LocalDate actualEndTime = projectInfo.getActualEndTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
                    LocalDate planEndTime = projectInfo.getPlanEndTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
                    if (actualEndTime.isAfter(planEndTime)) {
                        overdueCompletionNum = overdueCompletionNum + 1;//逾期完成
                    }else {
                        completionNum = completionNum + 1;//已完成
                    }
                    continue;
                }
                //已终止
                if (StringUtils.equals(projectInfo.getProStatus(), PlmEnums.ProStatus.END.getCode())) {
                    endNum = endNum + 1;
                    continue;
                }
                //执行中
                if (StringUtils.equals(projectInfo.getProStatus(), PlmEnums.ProStatus.EXECUT.getCode())) {
                        LocalDate localDate = new Date().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();//当前时间
                        LocalDate planEndTime = projectInfo.getPlanEndTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();//计划结束时间
                        //逾期执行中
                        if (localDate.isAfter(planEndTime)) {
                            overdueExecuteNum = overdueExecuteNum + 1;
                        }else {
                            executeNum = executeNum + 1;
                        }
                    continue;
                }
                //暂停
                if (StringUtils.equals(projectInfo.getProStatus(), PlmEnums.ProStatus.PAUSE.getCode())) {
                    pauseNum = pauseNum + 1;
                    continue;
                }
//                //逾期完成
//                if (StringUtils.equals(projectInfo.getProStatus(), PlmEnums.ProStatus.FINISH.getCode())) {
//                    if (projectInfo.getActualEndTime() != null){
//                        LocalDate actualEndTime = projectInfo.getActualEndTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
//                        LocalDate planEndTime = projectInfo.getPlanEndTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
//                        if (actualEndTime.isAfter(planEndTime)) {
//                            overdueCompletionNum = overdueCompletionNum + 1;
//                        }
//                    }
//                    continue;
//                }
//            }
//            //逾期执行中
//            if(StringUtils.equals(projectInfo.getProStatus(), PlmEnums.ProStatus.EXECUT.getCode())){
//                LocalDate actualStartTime = projectInfo.getActualStartTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
//                LocalDate planStartTime = projectInfo.getPlanStartTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
//                if (actualStartTime.isAfter(planStartTime)) {
//                    overdueExecuteNum = overdueExecuteNum + 1;
//                }
//            }
        }
        //查询对应的项目类型有多少
        Dict dict = JpaUtil.linq(Dict.class).equal("dictCode", "ERP_PROJECT_INFO_PRO_TYPE").findOne();
        List<DictItem> dictItemList = JpaUtil.linq(DictItem.class).equal("dictId", dict.getId()).list();
        List<ProjectReport> projectReports = new ArrayList<>();
        for (DictItem dictItem : dictItemList) {
            ProjectReport projectReport = new ProjectReport();
            Criteria c = Criteria.create();
//            c.addCriterion("createTime",Operator.GE,startDate);
//            c.addCriterion("createTime",Operator.LE,endDate);
            c.addCriterion("infoDeptId",Operator.IN,deptCodes);//对应的公司部门
            c.addCriterion("proType", Operator.EQ,dictItem.getItemValue());
            List<ProjectInfo> typeList = JpaUtil.linq(ProjectInfo.class).where(c).list();
            projectReport.setProType(dictItem.getItemValue());
            projectReport.setProTypeNum(typeList.size());
            projectReport.setProjectTotal(list.size());
            projectReport.setNewNum(newNum);
            projectReport.setCompletionNum(completionNum);
            projectReport.setOverdueExecuteNum(overdueExecuteNum);
            projectReport.setOverdueCompletionNum(overdueCompletionNum);
            projectReport.setExecuteNum(executeNum);
            projectReport.setPauseNum(pauseNum);
            projectReport.setEndNum(endNum);
            projectReports.add(projectReport);
        }
        return projectReports;
    }

    /**
     * 获取部门下所有子部门的编码
     * @param dept
     * @return
     */
    private List<String> getchildren(Dept dept) {
        List<String> deptCodes = new ArrayList<>();
        List<Dept> deptList = JpaUtil.linq(Dept.class).equal("faDeptId", dept.getId()).list();
        if (deptList != null && deptList.size() > 0) {
            for (Dept dept1 : deptList) {
                deptCodes.add(dept1.getDeptCode());
                deptCodes.addAll(getchildren(dept1));
            }
        }
        return deptCodes;
    }

    @Override
    @Transactional
    public List<ProjectReport> getTypeCount(String infoDeptId) {

        //查询部门以及子部门
        Dept dept = JpaUtil.linq(Dept.class).equal("deptCode", infoDeptId).findOne();
        List<String> deptCodes    =  getchildren(dept);
        deptCodes.add(dept.getDeptCode());
        // 获取当前日期
        LocalDate currentDate = LocalDate.now();
        // 从当前日期中提取年份
        int year = currentDate.getYear();
        Calendar calendar = new GregorianCalendar(year, Calendar.JANUARY, 1, 0, 0, 0);
        calendar.set(Calendar.MILLISECOND, 0); // 精确到秒，所以毫秒设为0
        Date startDate = calendar.getTime();
        calendar.set(Calendar.MONTH, Calendar.DECEMBER);
        calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        calendar.set(Calendar.MILLISECOND, 999); // 如果需要精确到毫秒的最后一位，可以设为999，否则设为0以保持秒级精度
        // 但由于要求精确到秒，这里我们再次将其设为0以保持一致性
        calendar.set(Calendar.MILLISECOND, 0);
        Date endDate = calendar.getTime();
        Criteria criteria = Criteria.create();
//        criteria.addCriterion("createTime",Operator.GE,startDate);
//        criteria.addCriterion("createTime",Operator.LE,endDate);
        criteria.addCriterion("infoDeptId",Operator.IN,deptCodes);//对应的公司部门
//        List<ProjectInfo> list = JpaUtil.linq(ProjectInfo.class).where(criteria).list();
        //查询对应的项目类型有多少
        Dict dict = JpaUtil.linq(Dict.class).equal("dictCode", "ERP_PROJECT_INFO_PRO_TYPE").findOne();
        List<DictItem> dictItemList = JpaUtil.linq(DictItem.class).equal("dictId", dict.getId()).list();
        List<ProjectReport> projectReports = new ArrayList<>();
        for (DictItem dictItem : dictItemList) {
            int newNum = 0;//新增数量
            int completionNum = 0;//已完成数量
            int overdueCompletionNum = 0;//逾期完成数量
            int executeNum = 0;//执行中数量
            int overdueExecuteNum = 0;//逾期执行中数量
            int pauseNum = 0;//暂停数量
            int endNum = 0;//已终止数量
            ProjectReport projectReport = new ProjectReport();
            Criteria c = Criteria.create();
//            c.addCriterion("createTime",Operator.GE,startDate);
//            c.addCriterion("createTime",Operator.LE,endDate);
            c.addCriterion("infoDeptId",Operator.IN,deptCodes);//对应的公司部门
            c.addCriterion("proType", Operator.EQ,dictItem.getItemValue());
            List<ProjectInfo> list = JpaUtil.linq(ProjectInfo.class).where(c).list();
            for (ProjectInfo projectInfo : list){
                //新增数量
                if (StringUtils.equals(projectInfo.getProStatus(), PlmEnums.ProStatus.NEW.getCode())) {
                    newNum = newNum + 1;
                    continue;
                }
                //已完成
                if (StringUtils.equals(projectInfo.getProStatus(), PlmEnums.ProStatus.FINISH.getCode())) {
                    LocalDate actualEndTime = projectInfo.getActualEndTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
                    LocalDate planEndTime = projectInfo.getPlanEndTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
                    if (actualEndTime.isAfter(planEndTime)) {
                        overdueCompletionNum = overdueCompletionNum + 1;//逾期完成
                    }else{
                        completionNum = completionNum + 1;
                    }
                    continue;
                }
                //已终止
                if (StringUtils.equals(projectInfo.getProStatus(), PlmEnums.ProStatus.END.getCode())) {
                    endNum = endNum + 1;
                    continue;
                }
                //执行中
                if (StringUtils.equals(projectInfo.getProStatus(), PlmEnums.ProStatus.EXECUT.getCode())) {
                    LocalDate localDate = new Date().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();//当前时间
                    LocalDate planEndTime = projectInfo.getPlanEndTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();//计划结束时间
                    //逾期执行中
                    if (localDate.isAfter(planEndTime)) {
                        overdueExecuteNum = overdueExecuteNum + 1;
                    }else{
                        executeNum = executeNum + 1;
                    }
                    continue;
                }
                //暂停
                if (StringUtils.equals(projectInfo.getProStatus(), PlmEnums.ProStatus.PAUSE.getCode())) {
                    pauseNum = pauseNum + 1;
                    continue;
                }
//                //逾期完成
//                if (StringUtils.equals(projectInfo.getProStatus(), PlmEnums.ProStatus.FINISH.getCode())) {
//                    if (projectInfo.getActualEndTime() != null){
//                        LocalDate actualEndTime = projectInfo.getActualEndTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
//                        LocalDate planEndTime = projectInfo.getPlanEndTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
//                        if (actualEndTime.isAfter(planEndTime)) {
//                            overdueCompletionNum = overdueCompletionNum + 1;
//                        }
//                    }
//                    continue;
//                }
            }
            projectReport.setProType(dictItem.getItemValue());
            projectReport.setNewNum(newNum);
            projectReport.setCompletionNum(completionNum);
            projectReport.setOverdueExecuteNum(overdueExecuteNum);
            projectReport.setOverdueCompletionNum(overdueCompletionNum);
            projectReport.setExecuteNum(executeNum);
            projectReport.setPauseNum(pauseNum);
            projectReport.setEndNum(endNum);
            projectReports.add(projectReport);
        }
        return projectReports;
    }

    @Override
    @Transactional
    public ProjectReport getCompleteCount(String infoDeptId) {
        //查询部门以及子部门
        Dept dept = JpaUtil.linq(Dept.class).equal("deptCode", infoDeptId).findOne();
        List<String> deptCodes    =  getchildren(dept);
        deptCodes.add(dept.getDeptCode());
        // 获取当前日期
        LocalDate currentDate = LocalDate.now();
        // 从当前日期中提取年份
        int year = currentDate.getYear();
        Calendar calendar = new GregorianCalendar(year, Calendar.JANUARY, 1, 0, 0, 0);
        calendar.set(Calendar.MILLISECOND, 0); // 精确到秒，所以毫秒设为0
        Date startDate = calendar.getTime();
        calendar.set(Calendar.MONTH, Calendar.DECEMBER);
        calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        calendar.set(Calendar.MILLISECOND, 999); // 如果需要精确到毫秒的最后一位，可以设为999，否则设为0以保持秒级精度
        // 但由于要求精确到秒，这里我们再次将其设为0以保持一致性
        calendar.set(Calendar.MILLISECOND, 0);
        Date endDate = calendar.getTime();
        Criteria criteria = Criteria.create();
//        criteria.addCriterion("createTime",Operator.GE,startDate);
//        criteria.addCriterion("createTime",Operator.LE,endDate);
        criteria.addCriterion("infoDeptId",Operator.IN,deptCodes);//对应的公司部门
        List<ProjectInfo> list = JpaUtil.linq(ProjectInfo.class).where(criteria).list();
        int completeNum = 0;//已完成数量
        int incompleteNum = 0;//未完成数量
        int endNum = 0;//已终止数量
        for (ProjectInfo projectInfo : list){
            //已完成
            if (StringUtils.equals(projectInfo.getProStatus(), PlmEnums.ProStatus.FINISH.getCode())) {
                completeNum = completeNum + 1;
                continue;
            }
            //已终止
            if (StringUtils.equals(projectInfo.getProStatus(), PlmEnums.ProStatus.END.getCode())) {
                endNum = endNum + 1;
                continue;
            }
            //未完成
            if(StringUtils.equals(projectInfo.getProStatus(), PlmEnums.ProStatus.NEW.getCode())
               ||StringUtils.equals(projectInfo.getProStatus(), PlmEnums.ProStatus.EXECUT.getCode())
               ||StringUtils.equals(projectInfo.getProStatus(), PlmEnums.ProStatus.PAUSE.getCode())){
                incompleteNum = incompleteNum + 1;
            }
        }
        ProjectReport projectReport = new ProjectReport();
        projectReport.setCompleteNum(completeNum);
        projectReport.setIncompleteNum(incompleteNum);
        projectReport.setEndNum(endNum);
        return projectReport;
    }

    @Override
    @Transactional
    public Page<ProjectInfo> getOverdueInfo(Pageable page,String infoDeptId) {
        //查询部门以及子部门
        Dept dept = JpaUtil.linq(Dept.class).equal("deptCode", infoDeptId).findOne();
        List<String> deptCodes    =  getchildren(dept);
        deptCodes.add(dept.getDeptCode());

        Criteria criteria = Criteria.create().addCriterion("infoDeptId", Operator.IN, deptCodes);
        criteria.addCriterion("status",Operator.EQ,"0");
        Page<ProjectInfo> projectInfoList = projectInfoService.listPage(ProjectInfo.class, page, criteria);
        for (ProjectInfo projectInfo : projectInfoList) {
            //判断任务是否延期
                //查找是否有逾期的任务，将第一个逾期的任务展示出来
                Criteria c = Criteria.create().addCriterion("proCode", Operator.EQ, projectInfo.getProCode());
                List<ProjectTask> tasks = projectTaskService.list(ProjectTask.class, c);

                //存逾期的任务
                List<ProjectTask> projectTasks = new ArrayList<>();
                for (ProjectTask task : tasks) {
                    if (StringUtils.equals(task.getTaskStatus(),"0")){
                        projectTasks.add(task);
                    }
                }

                ProjectTask earliestTask = null;
                //对逾期的任务进行判断，查看谁是第一个逾期的
                for (ProjectTask task : projectTasks) {
                    if (earliestTask == null || task.getCreateTime().before(earliestTask.getCreateTime())) {
                            earliestTask = task;
                    }
                }
                if (earliestTask != null){
                projectInfo.setTaskCode(earliestTask.getTaskCode());
                projectInfo.setTaskName(earliestTask.getTaskName());
                projectInfo.setHead(earliestTask.getHead());
            }
        }

        return projectInfoList;
    }

    @Override
    @Transactional
    public List<ProjectReport> getTaskCompleteNum(String infoDeptId) {
        //查询部门以及子部门
        Dept dept = JpaUtil.linq(Dept.class).equal("deptCode", infoDeptId).findOne();
        List<String> deptCodes    =  getchildren(dept);
        deptCodes.add(dept.getDeptCode());

        // 获取当前日期
        LocalDate currentDate = LocalDate.now();
        // 从当前日期中提取年份
        int year = currentDate.getYear();
        Calendar calendar = new GregorianCalendar(year, Calendar.JANUARY, 1, 0, 0, 0);
        calendar.set(Calendar.MILLISECOND, 0); // 精确到秒，所以毫秒设为0
        Date startDate = calendar.getTime();
        calendar.set(Calendar.MONTH, Calendar.DECEMBER);
        calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        calendar.set(Calendar.MILLISECOND, 999); // 如果需要精确到毫秒的最后一位，可以设为999，否则设为0以保持秒级精度
        // 但由于要求精确到秒，这里我们再次将其设为0以保持一致性
        calendar.set(Calendar.MILLISECOND, 0);
        Date endDate = calendar.getTime();
        Criteria criteria = Criteria.create();
//        criteria.addCriterion("createTime",Operator.GE,startDate);
//        criteria.addCriterion("createTime",Operator.LE,endDate);
        criteria.addCriterion("proStatus",Operator.IN,Arrays.asList("40","50"));
        criteria.addCriterion("infoDeptId",Operator.IN,deptCodes);//对应的公司部门
        List<ProjectInfo> list = JpaUtil.linq(ProjectInfo.class).where(criteria).list();

        List<ProjectReport> projectReports = new ArrayList<>();
        for (ProjectInfo projectInfo : list) {
            //只取已完成的任务
            Criteria criteria1 = Criteria.create().addCriterion("executionStatus", Operator.EQ, PlmEnums.ExecutionStatus.FINISHED.getCode());
            List<ProjectTask> projectTasks = JpaUtil.linq(ProjectTask.class).equal("proCode", projectInfo.getProCode()).where(criteria1).list();
            for (ProjectTask projectTask : projectTasks) {

                String head = projectTask.getHead();
                String subHead = head.substring(1, head.length() - 1);
                String[] split = subHead.split(",");
                for (String s : split) {
                    ProjectReport projectReport = new ProjectReport();
                    projectReport.setTaskHead(s);
                    projectReport.setTaskNum(1);
                    projectReports.add(projectReport);
                }
            }
        }
        //统计（）进行去重合并
        Map<String, Integer> taskHeadCountMap = projectReports.stream()
                .collect(Collectors.toMap(
                        ProjectReport::getTaskHead, // 作为键的 Function
                        ProjectReport::getTaskNum,  // 作为值的 Function（初始值）
                        Integer::sum                // 合并 Function，用于相同的键
                ));

        List<ProjectReport> mergedProjectReports = taskHeadCountMap.entrySet().stream()
                .map(entry -> {
                    ProjectReport report = new ProjectReport();
                    report.setTaskHead(entry.getKey());
                    report.setTaskNum(entry.getValue());
                    return report;
                })
                .collect(Collectors.toList());

        return mergedProjectReports;
    }
}
